﻿using System.Data;
using System.Dynamic;
using SqlSugar;
using WeDonekRpc.Model;
using WeDonekRpc.SqlSugar.Tran;
using WeDonekRpc.SqlSugar.VirtualQuery;

namespace WeDonekRpc.SqlSugar.Virtual
{
    public class VirtualRepository : IVirtualRepository
    {
        private readonly ISqlClientFactory _Factory;

        private readonly string _ConfigId;

        protected VirtualRepository ( ISqlClientFactory factory, string configId )
        {
            this._Factory = factory;
            this._ConfigId = configId;
        }
        private SqlSugarProvider _Provider;

        public SqlSugarProvider Provider
        {
            get
            {
                this._Provider ??= this._Factory.GetProvider(this._ConfigId);
                return this._Provider;
            }
        }
        public IVirtualQuery GetVirtualTable ( QueryStruct query )
        {
            VirtualQuery.VirtualQuery t = new VirtualQuery.VirtualQuery(this.Provider);
            t.Load(query);
            return t;
        }
        public ILocalTransaction ApplyTran ( bool isInherit = true )
        {
            return new LocalTransaction(this._Factory, isInherit);
        }
        public bool IsTable ( string tableName )
        {
            return this.Provider.DbMaintenance.IsAnyTable(tableName);
        }
        public void CreateTable<T> () where T : class
        {
            this.Provider.CodeFirst.InitTables<T>();
        }
        public void CreateTable<T> ( string tableName ) where T : class
        {
            this.Provider.CodeFirst.As<T>(tableName).InitTables<T>();
        }
        public IVirtualTable CreateTable ( string tableName, string show )
        {
            return new VirtualTable(this.Provider, tableName, show);
        }
        public bool Delete<IdentityId> ( string table, string col, IdentityId value )
        {
            string where = col + "=@id";
            return this.Provider.Deleteable<object>().AS(table).Where(where, new
            {
                id = value
            }).ExecuteCommandHasChange();
        }
        public bool Delete<IdentityId> ( string table, string col, IdentityId[] value )
        {
            string where = col + " in (@id)";
            return this.Provider.Deleteable<object>().AS(table).Where(where, new
            {
                id = value
            }).ExecuteCommandHasChange();
        }
        public void Insert ( string table, Dictionary<string, object> values )
        {
            _ = this.Provider.Insertable(values).AS(table).ExecuteCommand();
        }
        public int Insert ( DataTable table )
        {
            return this._Provider.Fastest<DataTable>().AS(table.TableName).BulkCopy(table);
        }
        public void Insert ( string table, Func<object> values )
        {
            _ = this.Provider.InsertableByDynamic(values).AS(table).ExecuteCommand();
        }
        public bool Update ( string table, Dictionary<string, object> values, string identityId )
        {
            return this.Provider.Updateable(values).AS(table).WhereColumns(identityId).ExecuteCommandHasChange();
        }
        public bool Update ( string table, Dictionary<string, object> values, string[] identityIds )
        {
            return this.Provider.Updateable(values).AS(table).WhereColumns(identityIds).ExecuteCommandHasChange();
        }
        public bool Update ( string table, Func<object> values, string identityId )
        {
            return this.Provider.UpdateableByDynamic(values).AS(table).WhereColumns(identityId).ExecuteCommandHasChange();
        }
        public bool Update ( string table, Func<object> values, string[] identityId )
        {
            return this.Provider.UpdateableByDynamic(values).AS(table).WhereColumns(identityId).ExecuteCommandHasChange();
        }
        public IUpdateable<object> Update ( string table )
        {
            return this.Provider.Updateable<object>().AS(table);
        }
        public ISugarQueryable<ExpandoObject> GetQueryable ( string table )
        {
            return this._Factory.GetQueryable<ExpandoObject>(this._ConfigId).AS(table, "a");
        }
        public ISugarQueryable<ExpandoObject> GetQueryable ( string table, List<IConditionalModel> where )
        {
            if ( where == null )
            {
                return this._Factory.GetQueryable<ExpandoObject>(this._ConfigId).AS(table, "a");
            }
            return this._Factory.GetQueryable<ExpandoObject>(this._ConfigId).AS(table, "a").Where(where);
        }
        public ExpandoObject[] GetAll ( string table )
        {
            return this.GetQueryable(table).ToArray();
        }
        public Result[] GetAll<Result> ( string table, string colName )
        {
            return this.GetQueryable(table).Select<Result>(colName).ToArray();
        }
        public ExpandoObject[] Gets ( string table, List<SelectModel> selects )
        {
            return this.GetQueryable(table).Select(selects).ToArray();
        }
        public ExpandoObject[] Gets ( string table, List<IConditionalModel> where, string[] selects )
        {
            List<SelectModel> list = selects.Select(c => new SelectModel
            {
                FieldName = c
            }).ToList();
            return this.GetQueryable(table).Where(where).Select(list).ToArray();
        }
        public ExpandoObject[] Gets ( string table, List<IConditionalModel> where, List<SelectModel> selects )
        {
            if ( where == null )
            {
                return this.GetQueryable(table).Select(selects).ToArray();
            }
            return this.GetQueryable(table).Where(where).Select(selects).ToArray();
        }
        public Result[] Gets<Result> ( string table, List<IConditionalModel> where, string colName )
        {
            if ( where == null )
            {
                return this.GetQueryable(table).Select<Result>(colName).ToArray();
            }
            return this.GetQueryable(table).Where(where).Select<Result>(colName).ToArray();
        }
        public ExpandoObject[] Gets ( string table, List<IConditionalModel> where )
        {
            return this.GetQueryable(table).Where(where).SelectAll().ToArray();
        }
        public ExpandoObject Get ( string table, List<IConditionalModel> where )
        {
            return this.GetQueryable(table).Where(where).SelectAll().First();
        }
        public ExpandoObject Get ( string table, List<IConditionalModel> where, List<SelectModel> selects )
        {
            return this.GetQueryable(table).Where(where).Select(selects).First();
        }
        public ExpandoObject Get ( string table, List<IConditionalModel> where, params string[] cols )
        {
            List<SelectModel> list = cols.Select(c => new SelectModel
            {
                FieldName = c
            }).ToList();
            return this.GetQueryable(table).Where(where).Select(list).First();
        }

        public Result Get<Result> ( string table, List<IConditionalModel> where, string colName )
        {
            return this.GetQueryable(table).Where(where).Select<Result>(colName).First();
        }
        public ExpandoObject[] Query ( string table, List<IConditionalModel> where, List<SelectModel> selects, IBasicPage pager, out int count )
        {
            ISugarQueryable<ExpandoObject> queryable = this.GetQueryable(table, where);
            count = queryable.Clone().Count();
            return queryable.Select(selects).OrderBy(pager.OrderBy).Skip(( pager.Index - 1 ) * pager.Size).Take(pager.Size).ToArray();
        }
        public ExpandoObject[] Query ( string table, IBasicPage pager, out int count )
        {
            ISugarQueryable<ExpandoObject> queryable = this.GetQueryable(table);
            count = queryable.Clone().Count();
            if ( pager.OrderBy == null )
            {
                return queryable.Skip(( pager.Index - 1 ) * pager.Size).Take(pager.Size).ToArray();
            }
            return queryable.OrderBy(pager.OrderBy).Skip(( pager.Index - 1 ) * pager.Size).Take(pager.Size).ToArray();
        }
        public ExpandoObject[] Query ( string table, List<IConditionalModel> where, IBasicPage pager, out int count )
        {
            ISugarQueryable<ExpandoObject> queryable = this.GetQueryable(table, where);
            count = queryable.Clone().Count();
            return queryable.OrderBy(pager.OrderBy).Skip(( pager.Index - 1 ) * pager.Size).Take(pager.Size).ToArray();
        }

        public ExpandoObject[] Query ( string table, List<IConditionalModel> where, string[] cols, IBasicPage pager, out int count )
        {
            List<SelectModel> list = cols.Select(c => new SelectModel
            {
                FieldName = c
            }).ToList();
            ISugarQueryable<ExpandoObject> queryable = this.GetQueryable(table, where);
            count = queryable.Clone().Count();
            return queryable.Select(list).OrderBy(pager.OrderBy).Skip(( pager.Index - 1 ) * pager.Size).Take(pager.Size).ToArray();
        }
        public int Count ( string table, List<IConditionalModel> where )
        {
            return this.GetQueryable(table, where).Count();
        }
        public Result Max<Result> ( string table, List<IConditionalModel> where, string colName )
        {
            return this.GetQueryable(table, where).Max<Result>(colName);
        }
        public Result Min<Result> ( string table, List<IConditionalModel> where, string filed )
        {
            return this.GetQueryable(table, where).Min<Result>(filed);
        }
        public bool IsExists ( string table, List<IConditionalModel> where, string col )
        {
            return this.GetQueryable(table).Where(where).Select(col).First() != null;
        }
        public bool IsExists ( string table, List<IConditionalModel> where )
        {
            return this.GetQueryable(table).Where(where).Any();
        }
        public IVirtualQueue BeginQueue ()
        {
            return new VirtualQueue(this.Provider);
        }

        public ExpandoObject[] GroupBy ( string table, List<IConditionalModel> where, List<SelectModel> selects, List<GroupByModel> groupBy )
        {
            return this.GetQueryable(table).Where(where).GroupBy(groupBy).Select(selects).ToArray();
        }
    }
}
